to VCPUs.
Signed-off-by: Keir Fraser <keir@xensource.com>
int cpu = smp_processor_id();
per_cpu(resched_irq, cpu) =
- bind_ipi_on_cpu_to_irq(cpu, RESCHEDULE_VECTOR);
+ bind_ipi_to_irq(RESCHEDULE_VECTOR);
sprintf(resched_name[cpu], "resched%d", cpu);
BUG_ON(request_irq(per_cpu(resched_irq, cpu), smp_reschedule_interrupt,
SA_INTERRUPT, resched_name[cpu], NULL));
per_cpu(callfunc_irq, cpu) =
- bind_ipi_on_cpu_to_irq(cpu, CALL_FUNCTION_VECTOR);
+ bind_ipi_to_irq(CALL_FUNCTION_VECTOR);
sprintf(callfunc_name[cpu], "callfunc%d", cpu);
BUG_ON(request_irq(per_cpu(callfunc_irq, cpu),
smp_call_function_interrupt,
spin_unlock(&irq_mapping_update_lock);
}
-int bind_ipi_on_cpu_to_irq(int cpu, int ipi)
+int bind_ipi_on_cpu_to_irq(int ipi)
{
evtchn_op_t op;
int evtchn, irq;
+ int cpu = smp_processor_id();
spin_lock(&irq_mapping_update_lock);
if ( (evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]) == 0 )
{
- op.cmd = EVTCHNOP_bind_ipi;
- op.u.bind_ipi.ipi_vcpu = cpu;
+ op.cmd = EVTCHNOP_bind_ipi;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, cpu);
evtchn = op.u.bind_ipi.port;
spin_lock(&irq_mapping_update_lock);
- op.cmd = EVTCHNOP_rebind;
- op.u.rebind.port = evtchn;
- op.u.rebind.vcpu = newcpu;
+ op.cmd = EVTCHNOP_bind_vcpu;
+ op.u.bind_vcpu.port = evtchn;
+ op.u.bind_vcpu.vcpu = newcpu;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
printk(KERN_INFO "Failed to rebind IPI%d to CPU%d\n",ipi,newcpu);
spin_lock(&irq_mapping_update_lock);
- op.cmd = EVTCHNOP_rebind;
- op.u.rebind.port = evtchn;
- op.u.rebind.vcpu = newcpu;
+ op.cmd = EVTCHNOP_bind_vcpu;
+ op.u.bind_vcpu.port = evtchn;
+ op.u.bind_vcpu.vcpu = newcpu;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
printk(KERN_INFO "Failed to rebind IRQ%d to CPU%d\n",irq,newcpu);
spin_unlock(&irq_mapping_update_lock);
}
-void unbind_ipi_on_cpu_from_irq(int cpu, int ipi)
+void unbind_ipi_from_irq(int ipi)
{
evtchn_op_t op;
+ int cpu = smp_processor_id();
int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi];
int irq = irq_to_evtchn[evtchn];
/* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */
extern int bind_virq_to_irq(int virq);
extern void unbind_virq_from_irq(int virq);
-extern int bind_ipi_on_cpu_to_irq(int cpu, int ipi);
-extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi);
+extern int bind_ipi_to_irq(int ipi);
+extern void unbind_ipi_from_irq(int ipi);
extern int bind_evtchn_to_irq(int evtchn);
extern void unbind_evtchn_from_irq(int evtchn);
/* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */
extern int bind_virq_to_irq(int virq);
extern void unbind_virq_from_irq(int virq);
-extern int bind_ipi_on_cpu_to_irq(int cpu, int ipi);
-extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi);
+extern int bind_ipi_to_irq(int ipi);
+extern void unbind_ipi_from_irq(int ipi);
extern int bind_evtchn_to_irq(int evtchn);
extern void unbind_evtchn_from_irq(int evtchn);
chn1->u.interdomain.remote_dom = d2;
chn1->u.interdomain.remote_port = (u16)port2;
- chn1->notify_vcpu_id = 0;
chn1->state = ECS_INTERDOMAIN;
chn2->u.interdomain.remote_dom = d1;
chn2->u.interdomain.remote_port = (u16)port1;
- chn2->notify_vcpu_id = 0;
chn2->state = ECS_INTERDOMAIN;
out:
{
struct evtchn *chn;
struct domain *d = current->domain;
- int port, ipi_vcpu = bind->ipi_vcpu;
-
- if ( (ipi_vcpu >= MAX_VIRT_CPUS) || (d->vcpu[ipi_vcpu] == NULL) )
- return -EINVAL;
+ int port;
spin_lock(&d->evtchn_lock);
{
chn = evtchn_from_port(d, port);
chn->state = ECS_IPI;
- chn->notify_vcpu_id = ipi_vcpu;
+ chn->notify_vcpu_id = current->vcpu_id;
}
spin_unlock(&d->evtchn_lock);
chn = evtchn_from_port(d, port);
- chn->notify_vcpu_id = 0;
-
d->pirq_to_evtchn[pirq] = port;
rc = pirq_guest_bind(d->vcpu[0], pirq,
!!(bind->flags & BIND_PIRQ__WILL_SHARE));
BUG();
}
- chn1->state = ECS_FREE;
+ /* Reset binding to vcpu0 when the channel is freed. */
+ chn1->state = ECS_FREE;
+ chn1->notify_vcpu_id = 0;
out:
if ( d2 != NULL )
status->u.virq = chn->u.virq;
break;
case ECS_IPI:
- status->status = EVTCHNSTAT_ipi;
- status->u.ipi_vcpu = chn->notify_vcpu_id;
+ status->status = EVTCHNSTAT_ipi;
break;
default:
BUG();
}
+ status->vcpu = chn->notify_vcpu_id;
+
out:
spin_unlock(&d->evtchn_lock);
put_domain(d);
return rc;
}
-static long evtchn_rebind(evtchn_rebind_t *bind)
+static long evtchn_bind_vcpu(evtchn_bind_vcpu_t *bind)
{
struct domain *d = current->domain;
int port = bind->port;
int vcpu = bind->vcpu;
struct evtchn *chn;
- long rc = 0;
+ long rc = 0;
+
+ if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) )
+ return -EINVAL;
spin_lock(&d->evtchn_lock);
}
chn = evtchn_from_port(d, port);
- chn->notify_vcpu_id = vcpu;
+ switch ( chn->state )
+ {
+ case ECS_UNBOUND:
+ case ECS_INTERDOMAIN:
+ case ECS_PIRQ:
+ chn->notify_vcpu_id = vcpu;
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
out:
spin_unlock(&d->evtchn_lock);
rc = -EFAULT;
break;
- case EVTCHNOP_rebind:
- rc = evtchn_rebind(&op.u.rebind);
- if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
- rc = -EFAULT;
+ case EVTCHNOP_bind_vcpu:
+ rc = evtchn_bind_vcpu(&op.u.bind_vcpu);
break;
default:
* This makes sure that old versions of dom0 tools will stop working in a
* well-defined way (rather than crashing the machine, for instance).
*/
-#define DOM0_INTERFACE_VERSION 0xAAAA100D
+#define DOM0_INTERFACE_VERSION 0xAAAA100E
/************************************************************************/
*/
#define EVTCHNOP_bind_ipi 7
typedef struct evtchn_bind_ipi {
- /* IN parameters. */
- u32 ipi_vcpu;
/* OUT parameters. */
u32 port;
} evtchn_bind_ipi_t;
#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */
u32 status;
+ u32 vcpu; /* VCPU to which this channel is bound. */
union {
struct {
domid_t dom;
} interdomain; /* EVTCHNSTAT_interdomain */
u32 pirq; /* EVTCHNSTAT_pirq */
u32 virq; /* EVTCHNSTAT_virq */
- u32 ipi_vcpu; /* EVTCHNSTAT_ipi */
} u;
} evtchn_status_t;
-#define EVTCHNOP_rebind 8
-typedef struct {
+/*
+ * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
+ * event is pending.
+ * NOTES:
+ * 1. IPI- and VIRQ-bound channels always notify the vcpu that initialised
+ * the binding. This binding cannot be changed.
+ * 2. All other channels notify vcpu0 by default. This default is set when
+ * the channel is allocated (a port that is freed and subsequently reused
+ * has its binding reset to vcpu0).
+ */
+#define EVTCHNOP_bind_vcpu 8
+typedef struct evtchn_bind_vcpu {
/* IN parameters. */
- u32 port; /* 0 */
- u32 vcpu; /* 4 */
-} evtchn_rebind_t; /* 8 bytes */
+ u32 port;
+ u32 vcpu;
+} evtchn_bind_vcpu_t;
typedef struct evtchn_op {
u32 cmd; /* EVTCHNOP_* */
evtchn_close_t close;
evtchn_send_t send;
evtchn_status_t status;
- evtchn_rebind_t rebind;
+ evtchn_bind_vcpu_t bind_vcpu;
} u;
} evtchn_op_t;